//
//  ViewController.swift
//  2048
//
//  Created by onemade on 8/23/16.
//  Copyright © 2016 CNPC. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scoreLabel: UILabel!
    @IBOutlet weak var stepCountLabel: UILabel!
    @IBOutlet weak var mainView: UIView!
    var score: Int = 0
    var stepCount: Int = 0
    var dimension: Int = 4
    var threshold: Int = 512
    var thinPadding: CGFloat = 3.0
    var thickPadding: CGFloat = 6.0
    var viewPadding: CGFloat = 10.0
    var tilePadding: CGFloat?
    var mainViewWidth: CGFloat = 400.0
    var tileWidth: CGFloat?
    var tiles: Dictionary<NSIndexPath,UIView>?
    
    var gameBoard: SquareGameboard<TileObject>?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tiles = Dictionary()
        mainView.layer.cornerRadius = 10
        setupSwipeController()
        tilePadding = dimension > 5 ? thinPadding : thickPadding
        let v1 = mainViewWidth - tilePadding!*(CGFloat(dimension + 1))
        
        tileWidth = CGFloat(floorf(CFloat(v1)))/CGFloat(dimension)
        
        initBackgroundView()
        
        gameBoard = SquareGameboard(dimension: dimension, initialValue: .Empty)
        
        insertTileAtRandomLocation(2)
        insertTileAtRandomLocation(2)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

//MARK: - setup swipe controllers
extension ViewController{
    func setupSwipeController() {
        let upSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.upCommand(_:)))
        upSwipe.numberOfTouchesRequired = 1
        upSwipe.direction = .Up
        view.addGestureRecognizer(upSwipe)
        
        let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.downCommand(_:)))
        downSwipe.numberOfTouchesRequired = 1
        downSwipe.direction = .Down
        view.addGestureRecognizer(downSwipe)
        
        let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.leftCommand(_:)))
        leftSwipe.numberOfTouchesRequired = 1
        leftSwipe.direction = .Left
        view.addGestureRecognizer(leftSwipe)
        
        let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.rightCommand(_:)))
        rightSwipe.numberOfTouchesRequired = 1
        rightSwipe.direction = .Right
        view.addGestureRecognizer(rightSwipe)
    }
    
    func upCommand(render: UIGestureRecognizer) {
        print("swipe up")
        swipeResult()
    }
    
    func downCommand(render: UIGestureRecognizer) {
        print("swipe down")
        swipeResult()
    }
    
    func leftCommand(render: UIGestureRecognizer) {
        print("swipe left")
        swipeResult()
    }
    
    func rightCommand(render: UIGestureRecognizer) {
        print("swipe right")
        swipeResult()
    }
    
    func swipeResult() {
        self.stepCount = self.stepCount + 1
        updateStepCount()
        if isUserWon() {
            let alert = UIAlertController(title: "Congratulations", message: "You Won!", preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: { action in }))
            self.presentViewController(alert, animated: true, completion: {})
            return
        }
        let randomVal = Int(arc4random_uniform(10))
        insertTileAtRandomLocation(randomVal == 1 ? 4 : 2)
        if isUserLost() {
            let alert = UIAlertController(title: "Defeat", message: "You Lost...", preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: { action in }))
            self.presentViewController(alert, animated: true, completion: {})
        }
    }
}

//MARK: - Game Render
extension ViewController{
    func initBackgroundView() {
        var xCursor = tilePadding
        var yCursor: CGFloat?
        for _ in 0..<dimension {
            yCursor = tilePadding
            for _ in 0..<dimension{
                let tile = UIView(frame: CGRectMake(xCursor!, yCursor!, tileWidth!, tileWidth!))
                tile.layer.cornerRadius = 5
                tile.backgroundColor = UIColor.darkGrayColor()
                mainView.addSubview(tile)
                yCursor = yCursor! + tilePadding! + tileWidth!
            }
            xCursor = xCursor! + tilePadding! + tileWidth!
        }
    }
    
    func positionIsValid(pos: (Int, Int)) -> Bool {
        let (x, y) = pos
        return (x >= 0 && x < dimension && y >= 0 && y < dimension)
    }
    
    func insertTile(pos: (Int, Int), value: Int) {
        assert(positionIsValid(pos))
        let (row, col) = pos
        let x = tilePadding! + CGFloat(col) * (tilePadding! + tileWidth!)
        let y = tilePadding! + CGFloat(row) * (tilePadding! + tileWidth!)
        let radius:CGFloat = 5
        let tile = UIView(frame: CGRectMake(x, y, tileWidth!, tileWidth!))
        tile.layer.cornerRadius = radius
        tile.backgroundColor = UIColor.whiteColor()
        let numberLabel = UILabel(frame: CGRectMake(0, 0, tileWidth!, tileWidth!))
        numberLabel.text = "\(value)"
        numberLabel.textAlignment = NSTextAlignment.Center
        numberLabel.minimumScaleFactor = 0.5
        numberLabel.font = UIFont.systemFontOfSize(30)
        tile.addSubview(numberLabel)
        mainView.addSubview(tile)
        tiles![NSIndexPath(forRow: row, inSection: col)] = tile
        gameBoard![row, col] = TileObject.Tile(value)
    }
    
    func updateScore(score: Int) {
        self.score = self.score + score
        self.scoreLabel.text = "Score：\(self.score)"
    }
    func updateStepCount() {
        self.stepCountLabel.text = "Steps：\(self.stepCount)"
    }
    func reset() {
        for (_, tile) in tiles! {
            tile.removeFromSuperview()
        }
        tiles?.removeAll(keepCapacity: true)
    }
    func insertTileAtRandomLocation(value: Int) {
        let openSpots = gameboardEmptySpots()
        if openSpots.isEmpty {
            return
        }
        let idx = Int(arc4random_uniform(UInt32(openSpots.count - 1)))
        let (x, y) = openSpots[idx]
        insertTile((x,y), value: value)
    }
    
    /**
     获取没有数据的节点
     
     - returns: 节点集合
     */
    func gameboardEmptySpots() -> [(Int, Int)] {
        var buffer : [(Int, Int)] = []
        for i in 0..<dimension {
            for j in 0..<dimension {
                if case .Empty = gameBoard![i, j] {
                    buffer += [(i, j)]
                }
            }
        }
        return buffer
    }
    /**
     判读指定位置的值是否和下邻值相等
     
     - parameter location: 指定位置
     - parameter value:    指定位置的值
     
     - returns: 是否相等
     */
    func tileBelowHasTheSameValue(location: (Int, Int), value: Int) -> Bool {
        let (x, y) = location
        guard y != dimension - 1 else {
            return false
        }
        if case let .Tile(v) = gameBoard![x, y+1] {
            return v == value
        }
        return false
    }
    
    /**
     判读指定位置的值是否和右邻值相等
     
     - parameter location: 指定位置
     - parameter value:    指定位置的值
     
     - returns: 是否相等
     */
    func tileRightHasTheSameValue(location: (Int, Int), value: Int) -> Bool {
        let (x, y) = location
        guard x != dimension - 1 else{
            return false
        }
        if case let .Tile(v) = gameBoard![x+1, y]{
            return v == value
        }
        return false
    }
    
    /**
     判断是否完成
     - returns: 是否成功
     */
    func isUserWon() -> Bool {
        for i in 0..<dimension{
            for j in 0..<dimension{
                if case let .Tile(v) = gameBoard![i,j] where v >= threshold{
                    return true
                }
            }
        }
        return false
    }
    /**
     判断是否失败
     - returns: 是否失败
     */
    func isUserLost() -> Bool {
        guard gameboardEmptySpots().isEmpty else{
            return false
        }
        for i in 0..<dimension {
            for j in 0..<dimension {
                switch gameBoard![i,j] {
                case .Empty:
                    assert(false, "")
                case let .Tile(v):
                    if tileBelowHasTheSameValue((i, j), value: v) || tileRightHasTheSameValue((i, j), value: v) {
                        return false
                    }
                }
            }
        }
        return true
    }
    
    /**
     获取指定字体
     - returns: 字体类型
     */
    func fontForNumbers() -> UIFont {
        if let font = UIFont(name: "HelveticaNeue-Bold", size: 40) {
            return font
        }
        return UIFont.systemFontOfSize(40)
    }
}

// MARK: - Action
extension ViewController{
    func performMove(direction: MoveDirection) {
        
    }
}
